#ifndef GAME_H_
#define GAME_H_

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <memory.h>
#include <errno.h>
#include <fstream>
#include <sstream>
#include <string>
#include <list>


#include "joueur.h"
#include "threads.h"

using namespace std;

/*!
 * \class Game
 * \brief Serveur de partie. Représente une partie.
 * 
 * Hérite de la classe Threads.
 * Permet de créer une nouvelle partie, de connecter un joueur
 * à une partie existante.
 * Ecoute les mouvements de joueurs.
 * 
 */
class Game : public Threads
{
	//
	// Membres publics
	//

	public:

	/*!
	 *
	 * \brief Constructeur.
	 * \param portEcoute Port d'écoute TCP de connection des clients.
	 * \param portLecture Port de lecture UDP des mouvements des joueurs.
	 * \param portEcouteServeur Port d'écoute TCP des messages du serveur.
	 * \param portEcouteDistant Port d'écoute UDP du client distant.
	 * \param portEcouteServeurPrincipal Port d'écoute TCP du serveur principal distant.
	 * \param adresseServeurPrincipal Adresse du serveur principal distant.
	 *
	 */
	Game(u_short portEcoute, u_short portLecture, u_short portEcouteServeur,
			u_short portEcouteDistant, u_short portEcouteServeurPrincipal, string adresseServeurPrincipal);

	/*!
	 * \brief Destructeur
	 */
	~Game();



	
				//
				// Méthodes relatives à la reception/envoie de données.
				//

	/*!
	 *
	 * \brief Crée un socket UDP.
	 * \param port Le port du socket à créer.
	 * \return Un entier indiquant si la création s'est bien passée.
	 *
	 */
	int createUDPSock(u_short port);

	/*!
	 * 
	 * \brief Crée un socket TCP.
	 * \param port Le port du socket à créer.
	 * \return Un entier indiquant si la création s'est bien passée.
	 *
	 */	
	int createTCPSock(u_short port);
	
	
	/*!
	 *
	 * \brief Connexion au serveur principal. Envoie le code d'identification.
	 * \return Un entier indiquant si la connexion a été accepté.
	 *
	 */
	int serveurConnection();
	
	/*!
	 * 
	 * \brief Attend l'arrivée de nouveaux joueurs.
	 * 
	 */
	int * connectionWaiting();
	
	/*!
	 * 
	 * \brief Traite les nouveaux joeurs.
	 * 
	 */
	void * traiterClient();
	
	
	/*!
	 * 
	 * \brief Intercepte les données émises en UDP par les joueurs ().
	 * 
	 */
	void * receive();
	
	/*!
	 * 
	 * \brief Intercepte les données émises par le serveur.
	 * 
	 */
	int * receiveServeur();
	
	/*!
	 * 
	 * Traite les messages du serveur principal et de partie.
	 * 
	 */
	void traiteServeur();
	
	/*!
	 * 
	 * \brief Renvoie une réponse à l'émeteur.
	 * 
	 */	
	int sendToAll(struct sockaddr_in adresseDistante, string data);
	
	/*!
	 * 
	 * \brief Renvoie à tous les joueurs (sauf l'émeteur) de la partie
	 *  les nouvelles coordonnées et autres données à mettre à jour.
	 * 
	 */
	int sendOthers(struct sockaddr_in adresseDistante, string data);
	
	/*!
	 * 
	 * \brief Informe le serveur principal si la serveur de partie n'a pas planté.
	 * 
	 */
	int sendALive();




				//
				// Méthodes relatives à la création de threads.
				// Concrétise les virtuelles pures de la classe Threads.
				//

	/*!
	 * 
	 * \brief Lance la méthode connectionWaiting dans le thread d'ecoute.
	 * 
	 */
	virtual void traitementEcoute() {
		connectionWaiting();
	}
	/*!
	 * 
	 * \brief Lance la méthode traiterClient dans un nouveau thead temporaire.
	 * 
	 */
	virtual void traitementNouveauClient() {
		traiterClient();
	}



	/*!
	 *
	 * \brief Lance la méthode receive dans le thread de lecture.
	 *
	 */	
	virtual void traitementLecture() {
		receive();
	}



	/*!
	 *
	 * \brief Lance la méthode receiveServeur dans le thread d'ecoute du serveur.
	 *
	 */
	virtual void ecouteServeur() {
		receiveServeur();
	}
	/*!
	 *
	 * \brief Lance la méthode de traitement des messages du serveur principal et de partie.
	 *
	 */
	virtual void traitementServeur(){
		traiteServeur();
	}








				//
				// Méthodes relatives à la gestion des joueurs, etc.
				//

	/*!
	 *
	 * \brief Ajoute un joueur à une partie existante.
	 * \param joueur Le joueur a ajouter à la partie.
	 * \return Un entier indiquant si l'ajout s'est bien passée.
	 *
	 */
	int addPlayer(Joueur joueur);

	/*!
	 *
	 * \brief Déconnecte un joueur d'une partie.
	 * \param adresse L'adresse du joueur à supprimer de la partie.
	 * \return Un entier indiquant si la suppression s'est bien passée.
	 *
	 */
	int removePlayer(string adresse);

	/*!
	 *
	 * \brief Ecrit dans un fichier de log les événements particuliers d'une partie.
	 * \param message Le message à logguer.
	 *
	 * Écrit à la fin du fichier sans écraser les données déjà présentes.
	 * 
	 */
	void log(string message);







	//
	//	Membres privés.
	//

	private:

	int numberPlayer; /*!< Nombre de joueurs sur la partie. */
	int numberPacman; /*!< Nombre de pacman */
	int numberGhost; /*!< Nombre de fantomes */
	list<Joueur> gamerList; /*!< Liste de joueurs de la partie. */
	
	string jeton; /*!< Jeton permettant de vérifier que le joueur soit passé par le serveur principal */

	u_short portEcoute; /*!< Port d'écoute */
	u_short portLecture; /*!< Port de lecture */
	u_short portEcouteDistant; /*!< Port d'écoute distant */
	u_short portEcouteServeur; /*!< Port de communication avec le serveur principal */
	u_short portEcouteServeurPrincipal; /*!< Port d'écoute TCP du serveur principal */
	string adresseServeurPrincipal; /*!< Adresse du serveur principal */
	
	int sockEcoute; /*!< Socket d'écoute des clients */
	int sockLecture; /*!< Socket de lecture des mouvements des clients */
	int sockEcriture; /*!< Socket d'écriture */
	int sockEcouteServeur; /*!< Socket d'écoute du serveur */
	int msg_sock , msg_sock0;
	int sockServeur;
	int msg_sockServeur;
};

#endif /*GAME_H_*/
